package tech.waterism.topo.engine;

import tech.waterism.topo.calculator.ForecastCalculator;
import tech.waterism.topo.context.CalculationContext;
import tech.waterism.topo.handler.JointDispatchHandler;
import tech.waterism.topo.iterator.TopologyIterator;
import tech.waterism.topo.model.*;
import tech.waterism.topo.preprocessor.DataPreprocessor;

import java.util.Date;

/**
 * 调度引擎
 * 
 * <p>这是 calTopo() 方法的完整替代实现，完全独立于 service 层
 * <p>纯核心逻辑，不依赖任何 DTO 类
 * 
 * <h3>核心职责：</h3>
 * <ul>
 *   <li>编排整个调洪演算流程</li>
 *   <li>协调各个计算器和处理器</li>
 *   <li>管理计算状态和缓存</li>
 * </ul>
 * 
 * <h3>替代关系：</h3>
 * <pre>
 * 原方法：DispatchService.calTopo(TopoDataDto, Date, Date, Date, Map)
 *   ↓
 * 新方法：DispatchEngine.calculate(EngineRequest)
 * </pre>
 * 
 * @author waterism
 * @since 1.0.0
 */
public class DispatchEngine {
    
    private final DataPreprocessor preprocessor;
    private final ForecastCalculator forecastCalculator;
    private final JointDispatchHandler jointHandler;
    
    /**
     * 构造函数
     */
    public DispatchEngine() {
        this.preprocessor = new DataPreprocessor();
        this.forecastCalculator = new ForecastCalculator();
        this.jointHandler = new JointDispatchHandler();
    }
    
    /**
     * 执行调洪演算
     * 
     * <p>这是 calTopo() 的完整替代实现
     * 
     * @param request 调度请求（包含所有输入数据）
     * @return 调度响应（包含所有计算结果）
     */
    public EngineResponse calculate(EngineRequest request) {
        // ========== 1. 数据准备阶段 ==========
        CalculationContext context = prepareCalculation(request);
        
        // ========== 2. 拓扑遍历计算 ==========
        TopologyIterator iterator = new TopologyIterator(context.getNodes());
        
        while (iterator.hasNext()) {
            TopoNode node = iterator.next();
            
            // 2.1 检查缓存：如果已计算过，复用结果
            if (context.isCached(node.getStcd())) {
                reuseCalculationResult(node, context);
                continue;
            }
            
            // 2.2 预报计算：汇流计算
            forecastCalculator.calculate(node, context);
            
            // 2.3 调度计算：调用外部调度器（通过接口）
            if (request.getDispatcher() != null) {
                request.getDispatcher().dispatch(node, context);
            }
            
            // 2.4 统计计算：调用外部统计器（通过接口）
            if (request.getStatistician() != null) {
                request.getStatistician().calculate(node, context);
            }
            
            // 2.5 缓存结果
            context.cacheResult(node.getStcd(), new NodeResult(node.getStcd(), node.getData()));
            
            // 2.6 检查联调触发
            if (jointHandler.shouldTrigger(context)) {
                handleJointDispatch(context, request, iterator);
            }
        }
        
        // ========== 3. 后处理阶段 ==========
        EngineResponse response = buildResponse(context, request);
        
        return response;
    }
    
    /**
     * 数据准备阶段
     */
    private CalculationContext prepareCalculation(EngineRequest request) {
        // 1. 创建计算上下文
        CalculationContext context = new CalculationContext();
        context.setStartTime(request.getStartTime());
        context.setObservationStartTime(request.getObservationStartTime());
        context.setModifyTime(request.getModifyTime());
        context.setDispatchType(request.getDispatchType());
        context.setOutFlowType(request.getOutFlowType());
        context.setNodes(request.getNodes());
        context.setJointGroups(request.getJointGroups());
        
        // 2. 数据校验
        preprocessor.validateNodes(context.getNodes());
        
        // 3. 初始化分洪排洪数据
        preprocessor.initializeDiversionAndDischarge(context.getNodes());
        
        // 4. 构建节点索引映射
        preprocessor.buildNodeIndexMap(context.getNodes(), context);
        
        // 5. 构建联调映射
        preprocessor.buildJointDispatchMaps(context.getJointGroups(), context);
        
        return context;
    }
    
    /**
     * 复用计算结果
     */
    private void reuseCalculationResult(TopoNode node, CalculationContext context) {
        NodeResult cached = context.getCachedResult(node.getStcd());
        if (cached != null) {
            node.setData(cached.getData());
        }
    }
    
    /**
     * 处理联合调度
     */
    private void handleJointDispatch(CalculationContext context, EngineRequest request, 
                                    TopologyIterator iterator) {
        JointDispatchGroup group = context.getTriggeredGroup();
        if (group == null) {
            return;
        }
        
        // 1. 获取回溯位置
        int backtrackPos = jointHandler.getBacktrackPosition(group, context);
        
        // 2. 初始化联调节点（复用上游结果）
        jointHandler.initializeUpstreamNodes(group, context);
        
        // 3. 遍历联调节点
        for (TopoNode node : group.getNodes()) {
            // 预报计算（复用）
            forecastCalculator.calculate(node, context);
            
            // 调度计算
            if (request.getDispatcher() != null) {
                request.getDispatcher().dispatch(node, context);
            }
            
            // 统计计算
            if (request.getStatistician() != null) {
                request.getStatistician().calculate(node, context);
            }
            
            // 缓存到联调缓存
            context.cacheJointResult(node.getStcd(), new NodeResult(node.getStcd(), node.getData()));
        }
        
        // 4. 合并联调结果到主缓存
        context.mergeJointResults();
        
        // 5. 回溯到联调起点
        iterator.backtrackTo(backtrackPos);
        
        // 6. 清除触发状态
        context.clearTriggeredGroup();
        
        // 7. 从联调触发映射中移除该组
        context.getJointTriggerMap().remove(group.getJmsid());
    }
    
    /**
     * 构建响应结果
     */
    private EngineResponse buildResponse(CalculationContext context, EngineRequest request) {
        EngineResponse response = new EngineResponse();
        response.setNodes(context.getNodes());
        response.setSuccess(true);
        return response;
    }
}

